package com.itheima.log.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.log.domain.Log;
import com.itheima.log.service.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 切面处理类，操作日志记录
 */
@Aspect
@Component
public class LogAspect {

    @Autowired
    private LogService logService;

    /**
     * 设置操作日志切入点 记录操作日志 在注解的位置切入代码
     */
    @Pointcut("@annotation(com.itheima.log.aop.LogRec)")
    public void logRecPoinCut() {
    }

    /**
     * 每次操作后保存到记录表中
     *
     * @param joinPoint 切入点
     */
    @AfterReturning(value = "logRecPoinCut()")
    public void saveLog(JoinPoint joinPoint) throws Exception {
        saveLog(joinPoint, null);
    }

    /**
     * 每次操作后保存到记录表中，异常处理
     *
     * @param joinPoint 切入点
     * @param throwable 异常信息
     */
    @AfterThrowing(value = "logRecPoinCut()", throwing = "throwable")
    public void saveOperLog(JoinPoint joinPoint, Throwable throwable) throws Exception {
        saveLog(joinPoint, throwable);
    }

    private void saveLog(JoinPoint joinPoint, Throwable throwable) throws JsonProcessingException {
        //创建操作记录数据的对象
        Log log = new Log();

        //获取执行参数
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            //把参数转为Json格式的数据，方便存储
            log.setParam(new ObjectMapper().writeValueAsString(args));
        }

        // 通过获取织入点处的方法名
        String methodName = joinPoint.getSignature().getName();
        log.setMethod(methodName);

        //获取注解目标类的所有方法，并获取指定方法上的注解
        for (Method method : joinPoint.getTarget().getClass().getMethods()) {
            //遍历目标类的所有方法，获取当前使用的方法
            if (methodName.equals(method.getName())) {
                //获取方法上的注解对象
                LogRec logRec = method.getAnnotation(LogRec.class);
                //获取注解中的操作类型
                log.setType(logRec.type().name());
                //获取注解中的操作说明
                log.setDesc(logRec.desc());
                break;
            }
        }

        //封装错误信息
        if (throwable != null) {
    log.setError(throwable.getMessage());
    }

    //保存日志
    logService.save(log);

}
}